package net.seabookchen.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.seabookchen.pojo.BlogComment;
import net.seabookchen.pojo.BlogPost;
import net.seabookchen.pojo.BlogTag;
import net.seabookchen.pojo.wrapper.BlogPopularity;
import net.seabookchen.pojo.wrapper.BlogTagWrapper;
import net.seabookchen.service.BlogService;

import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.google.appengine.api.datastore.EntityNotFoundException;

@Controller
public class BlogContorller extends CommonController<BlogPost> {
	private static final Logger log = Logger.getLogger(BlogContorller.class
			.getName());
	private BlogService blogService;

	public BlogContorller() {
		if (blogService == null) {
			blogService = new BlogService();
		}
	}

	@RequestMapping(value = "/blogpost", method = RequestMethod.POST)
	public String createBlogPost(HttpServletRequest request,
			HttpServletResponse resp, Model model) {
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		String tags = request.getParameter("tags");

		BlogPost post = new BlogPost(title, content);

		String[] tagArr = null;
		if (tags != null && tags.length() > 0) {
			tagArr = tags.split(",");
		}
		if (tagArr != null && tagArr.length > 0) {
			post.setTags(blogService.transferTagId2KeySet(tagArr));
		}

		blogService.saveOrUpdateBlogEntry(post);
		populateModel(model, post,
				RequestMethod.POST + "-BlogPost-" + post.getId());
		log.info("Creat BlogPost: " + post.getTitle());
		return "showBlog";
	}

	@RequestMapping(value = "/allblogposts", method = RequestMethod.GET)
	public String allBlogPosts(HttpServletRequest request,
			HttpServletResponse resp, Model model) {
		List<BlogPost> posts = blogService.getPostDao().getAllPosts();
		model.addAttribute("action", "List All Blog Posts");
		model.addAttribute("entities", posts);
		log.info("List All Posts size: " + posts.size());
		return "showBlog";
	}

	@RequestMapping(value = "/listposts/popularity/{index}", method = RequestMethod.GET)
	public String listMostPopularPosts(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String index, Model model) {
		List<BlogPost> posts = blogService.getPostDao().listMostPopularPosts(
				Integer.valueOf(index));
		model.addAttribute("action", "List Most Popular Blog Posts");
		model.addAttribute("entities", posts);
		log.info("List Most Popular Blog Posts size: " + posts.size());
		return "showBlog";
	}

	@RequestMapping(value = "/listposts/creation/{index}", method = RequestMethod.GET)
	public String listNewestPosts(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String index, Model model) {
		List<BlogPost> posts = blogService.getPostDao().listLatestNewPosts(
				Integer.valueOf(index));
		// model.addAttribute("action", "List Newest Blog Posts");
		model.addAttribute("entities", posts);
		log.info("List Newest Posts size: " + posts.size());
		return "showBlogPreview";
	}

	@RequestMapping(value = "/listposts/modification/{index}", method = RequestMethod.GET)
	public String listLatestModifiedPosts(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String index, Model model) {
		List<BlogPost> posts = blogService.getPostDao()
				.listLatestModifiedPosts(Integer.valueOf(index));
		model.addAttribute("action", "List Latest Modified Blog Posts");
		model.addAttribute("entities", posts);
		log.info("List Latest Modified Posts size: " + posts.size());
		return "showBlog";
	}

	@RequestMapping(value = "/listposts/range", method = RequestMethod.GET)
	public String fetchPostsFromRange(HttpServletRequest request,
			HttpServletResponse resp, Model model) {
		String start = request.getParameter("start");
		String end = request.getParameter("end");
		List<BlogPost> posts = blogService.getPostDao().listPostsFromRange(
				Integer.valueOf(start), Integer.valueOf(end));
		mappingTags(posts, model);
		model.addAttribute("entities", posts);
		model.addAttribute("action", "Welcome to Seabook's Web Blog!!!");
		
		log.info("List Blog Posts from Range [ " + start + " -> " + end
				+ "] postSize: " + posts.size());
		return "showBlog";
	}

	@RequestMapping(value = "/blogpost/{id}", method = RequestMethod.GET)
	public String getBlogPost(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String id, Model model) {
		BlogPost post = null;
		List<BlogTag> tags = new ArrayList<BlogTag>();
		try {
			post = blogService.getPostDao().get(Long.valueOf(id));
			tags = blogService.getTagsByPost(post);
		} catch (NumberFormatException e) {
			log.log(Level.SEVERE, e.getMessage());
		} catch (EntityNotFoundException e) {
			log.log(Level.SEVERE, e.getMessage());
		}
		model.addAttribute("tags", tags);
		populateModel(model, post,
				RequestMethod.GET + "-BlogPost-" + post.getId());
		
		log.info("Get Blog Post: " + post.getTitle());
		return "showBlogPost";
	}

	@RequestMapping(value = "/blogpost/{id}", method = RequestMethod.DELETE)
	public String deleteBlogPost(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String id, Model model) {
		blogService.deleteBlogEntry(Long.valueOf(id));
		model.addAttribute("action", RequestMethod.DELETE + "-BlogPost-" + id);
		log.info("Delete Post: " + id);
		return "showBlog";
	}

	@RequestMapping(value = "/blogpost/{id}", method = RequestMethod.PUT)
	public String updateBlogPost(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String id, Model model) {
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		String tags = request.getParameter("tags");

		BlogPost post = new BlogPost(title, content);
		post.setId(Long.valueOf(id));

		String[] tagArr = null;
		if (tags != null && tags.length() > 0) {
			tagArr = tags.split(",");
		}
		if (tagArr != null && tagArr.length > 0) {
			post.setTags(blogService.transferTagId2KeySet(tagArr));
		}

		
		blogService.saveOrUpdateBlogEntry(post);
		populateModel(model, post,
				RequestMethod.PUT + "-BlogPost-" + post.getId());
		log.info("Update BlogPost: " + post.getTitle());
		return "showBlog";
	}

	@RequestMapping(value = "/blogpost/{id}/thumbsup", method = RequestMethod.PUT)
	public String thumbsUpBlogPost(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String id, Model model) {
		BlogPost post = blogService.addThumbs(Long.valueOf(id), true);
		populateModel(model, post, RequestMethod.PUT + "-BlogPost Thumbs up-"
				+ post.getId());
		log.info("Update BlogPost Thumbs up: " + post.getTitle());
		return "showBlog";
	}

	@RequestMapping(value = "/blogpost/{id}/thumbsdown", method = RequestMethod.PUT)
	public String thumbsDownBlogPost(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String id, Model model) {
		BlogPost post = blogService.addThumbs(Long.valueOf(id), false);
		populateModel(model, post, RequestMethod.PUT + "-BlogPost Thumbs Down-"
				+ post.getId());
		log.info("Update BlogPost Thumbs up: " + post.getTitle());
		return "showBlog";
	}

	@RequestMapping(value = "/blogpost/{postId}/comment", method = RequestMethod.POST)
	public String addComment2BlogPost(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String postId, Model model) {
		String username = request.getParameter("username");
		String email = request.getParameter("email");
		String url = request.getParameter("url");
		String content = request.getParameter("content");
		String safe = Jsoup.clean(content, Whitelist.basic().addEnforcedAttribute("code", "class", "prettyprint"));
		BlogComment comment = new BlogComment(username, email, url, safe);
		BlogPost post = blogService.addComment2Post(Long.valueOf(postId),
				comment);
		
		model.addAttribute("action", "Post Comment-" + comment.getId() + " to BlogPost-" + post.getId() + "successfully!" );
		model.addAttribute("comment", comment);
		
		log.info("add comment 2 BlogPost : " + post.getTitle());
		return "postSuccess";
	}

	@RequestMapping(value = "/blogpost/{postId}/comment/{commentId}", method = RequestMethod.DELETE)
	public String deleteCommentFromBlogPost(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String postId,
			@PathVariable String commentId, Model model) {
		BlogPost post = blogService.deleteCommentFromPost(Long.valueOf(postId),
				Long.valueOf(commentId));
		populateModel(model, post, RequestMethod.DELETE
				+ "-Delete comment from BlogPost-" + post.getId());
		log.info("Delete comment from BlogPost : " + post.getTitle());
		return "postSuccess";
	}
	
	@RequestMapping(value = "/blogpost/{postId}/comments", method = RequestMethod.GET)
	public String getComments4Post(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String postId,
			Model model) {
		BlogPost post = new BlogPost();
		post.setId(Long.valueOf(postId));
		List<BlogComment> comments = blogService.getCommentDao().getAllCommentsByPost(post);
		model.addAttribute("isBlogPage", true);
		model.addAttribute("entities", comments);
		log.info("All comments for Post : " + post.getId() + " Comments Size: " + comments.size());
		return "showComments";
	}

	@RequestMapping(value = "/blogpost/{postId}/tags", method = RequestMethod.GET)
	public String getTagsForBlogPost(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String postId, Model model) {
		BlogPost post = blogService.getOrCreatePost(Long.valueOf(postId));
		List<BlogTagWrapper> tags = blogService.getTagsWrapper(post);
		model.addAttribute("entities", tags);
		log.info("add Tag 2 BlogPost : " + post.getTitle());
		return "showTagsWrapper";
	}

	@RequestMapping(value = "/blogpost/{postId}/tag/{tagId}", method = RequestMethod.DELETE)
	public String deleteTagFromBlogPost(HttpServletRequest request,
			HttpServletResponse resp, @PathVariable String postId,
			@PathVariable String tagId, Model model) {
		BlogPost post = blogService.deleteTagFromPost(Long.valueOf(postId),
				Long.valueOf(tagId));
		populateModel(model, post, RequestMethod.DELETE
				+ "-Delete Tag from BlogPost-" + post.getId());
		log.info("Delete tag from BlogPost : " + post.getTitle());
		return "showBlog";	
	}

	@RequestMapping(value = "/blogpost/size", method = RequestMethod.GET)
	public String getTotalSize(HttpServletRequest request,
			HttpServletResponse resp, Model model) {
		int size = blogService.getPostDao().getTotalSize();
		model.addAttribute("totalSize", String.valueOf(size));
		log.info("Total Size : " + size);
		return "showBlog";

	}
	
	@RequestMapping(value = "/blogpost/buildPopularity", method = RequestMethod.POST)
	public String buildPostsPopularity(HttpServletRequest request,
			HttpServletResponse resp, Model model) {
		blogService.rebuildBlogPopularity();
		model.addAttribute("action", "Index the blog posts by the popularity(comments quantity) done!");
		return "restful";
	}
	
	
	@RequestMapping(value = "/blogpost/popular/{index}", method = RequestMethod.GET)
	public String getMostPopularPosts(HttpServletRequest request,
			HttpServletResponse resp,  @PathVariable String index, Model model) {
		List<BlogPopularity> blogs =  blogService.getPopularBlogs(Integer.valueOf(index));
		model.addAttribute("entities", blogs);
		log.info(RequestMethod.GET + "-Get the Most "  + index + " Popular Blog Posts");
		return "popularBlogs";
	}
	
	@RequestMapping(value = "/blogpost/posts/tag/{id}", method = RequestMethod.GET)
	public String getPostsByTag(HttpServletRequest request,
			HttpServletResponse resp,  @PathVariable String id, Model model) {
		BlogTag tag = null;
		try {
			tag = blogService.getTagDao().get(Long.valueOf(id));
		} catch (Exception e) {
			tag = new BlogTag();
			tag.setId(Long.valueOf(id));
		}
		List<BlogPost> posts = blogService.getPostDao().getAllPostsByTag(tag);
		mappingTags(posts, model);
		model.addAttribute("entities", posts);
		model.addAttribute("action", "List all the posts for '" + tag.getTag() + "'");
		return "showPostsByTag";
	}
	
	
	private void mappingTags(List<BlogPost> posts, Model model) {
		
		Map<Long, List<BlogTag>> tagMap = new HashMap<Long, List<BlogTag>>();
		
		for (BlogPost post : posts) {
			tagMap.put(post.getId(), blogService.getTagsByPost(post));
		}
		model.addAttribute("tagMap", tagMap);
	}

}
